package com.sc.service.impl;

import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.CacheableServiceImpl;
import com.sc.entity.CourseStages;
import com.sc.exception.ServiceException;
import com.sc.mapper.CourseStagesMapper;
import com.sc.service.CourseStagesService;
import org.springframework.stereotype.Service;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import static com.mybatisflex.core.query.QueryMethods.max;
import static com.sc.entity.table.CourseStagesTableDef.COURSE_STAGES;

/**
 * 授课阶段表 服务层实现。
 *
 * @author JoeZhou
 * @since 2024-09-14
 */
@Service
@CacheConfig(cacheNames = "courseStages")
public class CourseStagesServiceImpl extends CacheableServiceImpl<CourseStagesMapper, CourseStages> implements CourseStagesService {

    @Override
    @CacheEvict(allEntries = true)
    public boolean remove(QueryWrapper query) {
        return super.remove(query);
    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional
    public boolean removeById(Serializable id) {
        CourseStages entity = getById(id);
        if (entity == null)
            throw new ServiceException("未找到对应的菜单记录~");
        UpdateChain.of(CourseStages.class)
                .setRaw(CourseStages::getSort, "sort - 1")
                .where(CourseStages::getDirectionId).eq(entity.getDirectionId())
                .where(CourseStages::getSort).ge(entity.getSort())
                .update();
        return super.removeById(id);
    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional
    public boolean removeByIds(Collection<? extends Serializable> ids) {
        ids.forEach(id -> removeById(id));
        return true;
    }

    @Override
    @CacheEvict(allEntries = true)
    public boolean update(CourseStages entity, QueryWrapper query) {
        return super.update(entity, query);
    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional
    public boolean save(CourseStages entity) {
        QueryWrapper queryWrapper
                = QueryWrapper.create().select(max(COURSE_STAGES.SORT)).eq("direction_id", entity.getDirectionId());
        Integer maxSort = getObjAs(queryWrapper, Integer.class);
        if (maxSort == null) {
            entity.setSort(1);
        } else {
            if (entity.getSort() > maxSort) {
                entity.setSort(maxSort + 1);
            } else {
                UpdateChain.of(CourseStages.class)
                        .setRaw(CourseStages::getSort, "sort + 1")
                        .where(CourseStages::getDirectionId).eq(entity.getDirectionId())
                        .where(CourseStages::getSort).ge(entity.getSort())
                        .update();
            }
        }
        return super.save(entity);
    }

    @Override
    @CacheEvict(allEntries = true)
    public boolean updateById(CourseStages entity, boolean ignoreNulls) {
        QueryWrapper queryWrapper
                = QueryWrapper.create().select(max(COURSE_STAGES.SORT)).eq("id", entity.getId());
        Integer oldSort = getObjAs(queryWrapper, Integer.class);
        queryWrapper.clear();
        queryWrapper.select(max(COURSE_STAGES.SORT)).eq("direction_id", entity.getDirectionId());
        // 查询同级菜单中最大的序号
        Integer maxSort = getObjAs(queryWrapper, Integer.class);
        Integer newSort = entity.getSort();
        if (newSort > maxSort) {
            entity.setSort(maxSort);
            newSort = maxSort;
        }
        /*
        如果同级菜单中存在与 oldSort 和 newSort 之间的菜单需要 +1 和 -1
         */
        if (newSort < oldSort) {
            UpdateChain.of(CourseStages.class)
                    .setRaw(CourseStages::getSort, "sort + 1")
                    .where(CourseStages::getDirectionId).eq(entity.getDirectionId())
                    .where(CourseStages::getSort).ge(newSort)
                    .where(CourseStages::getSort).lt(oldSort)
                    .update();
        } else {
            if (newSort > oldSort) {
                UpdateChain.of(CourseStages.class)
                        .setRaw(CourseStages::getSort, "sort - 1")
                        .where(CourseStages::getDirectionId).eq(entity.getDirectionId())
                        .where(CourseStages::getSort).gt(oldSort)
                        .where(CourseStages::getSort).le(newSort)
                        .update();
            }
        }
        return super.updateById(entity, ignoreNulls);
    }

    @Override
    @CacheEvict(allEntries = true)
    public boolean updateBatch(Collection<CourseStages> entities, int batchSize) {
        return super.updateBatch(entities, batchSize);
    }

    @Override
    @Cacheable(key = "#id")
    public CourseStages getById(Serializable id) {
        return super.getById(id);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public CourseStages getOne(QueryWrapper query) {
        return super.getOne(query);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public <R> R getOneAs(QueryWrapper query, Class<R> asType) {
        return super.getOneAs(query, asType);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public Object getObj(QueryWrapper query) {
        return super.getObj(query);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public <R> R getObjAs(QueryWrapper query, Class<R> asType) {
        return super.getObjAs(query, asType);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public List<Object> objList(QueryWrapper query) {
        return super.objList(query);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public <R> List<R> objListAs(QueryWrapper query, Class<R> asType) {
        return super.objListAs(query, asType);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public List<CourseStages> list(QueryWrapper query) {
        return super.list(query);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public <R> List<R> listAs(QueryWrapper query, Class<R> asType) {
        return super.listAs(query, asType);
    }

    /**
     * @deprecated 无法通过注解进行缓存操作。
     */
    @Override
    @Deprecated
    public List<CourseStages> listByIds(Collection<? extends Serializable> ids) {
        return super.listByIds(ids);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #query.toSQL()")
    public long count(QueryWrapper query) {
        return super.count(query);
    }

    @Override
    @Cacheable(key = "#root.methodName + ':' + #page.getPageSize() + ':' + #page.getPageNumber() + ':' + #query.toSQL()")
    public <R> Page<R> pageAs(Page<R> page, QueryWrapper query, Class<R> asType) {
        return mapper.paginateWithRelationsAs(page.getPageNumber(), page.getPageSize(), query, asType);
    }

}
